#ifndef SOLVER_HPP
#define SOLVER_HPP

#include "Array.hpp"
#include <math.h>
#include <iostream>
#include <iomanip>
#include "Debug.hpp"
#include "Stencil.hpp"
#include <memory>
#define PI 3.14159265

class Solver
{
       
private:
  typedef std::shared_ptr<Array> PArray;
  typedef std::vector<PArray> Grids;

  size_t levels_;
  Grids x_;
  Grids f_;
  Grids r_;
  Stencil A_;
  Stencil I_;
  Stencil J_;
  void smoothGS(Array &x, const Array &f, size_t iter);
  void smoothGSRB(Array &x, const Array &f, size_t iter);
  void calcResidual(const Array &x, const Array &f, Array &r);
  void restrict(const Array &r, Array &f);
  void prolongateAndCorrect(const Array &e, Array &x);

public:

  explicit Solver(size_t nLevels):levels_(nLevels)
  {
    //Allocates memory for the arrays with smart pointers
    for(size_t l=0;l<levels_;++l)
      {
	x_.push_back(std::make_shared<Array>(l));
	f_.push_back(std::make_shared<Array>(l));
	r_.push_back(std::make_shared<Array>(l));
      }
    std::cout.setf(std::ios::boolalpha);
    for(size_t l=0;l<levels_;++l)
      std::cout<<"Level"<<l<<" Size "<<x_[l]->xsize()<<" Unique: "<<x_[l].unique()<<"\n";
    setStencil();
  }

  ~Solver()
  {
  }
       
  void setStencil();
  void mgSolve(Array& x, const Array& f, size_t cycles, size_t pre_iter, size_t post_iter);
       
};

#endif //SOLVER_HPP

